package naruto.datastructures.graph;

import java.io.*;
import java.util.*;
import naruto.common.GraphCommon;
import naruto.datastructures.instruction.Instruction;

/**
 *
 * @author nacuong
 */
public class Graph<T extends Node> extends Vector<T>{
  T initialNode;
  Vector<T> finalNodes;

  public Graph(){
    super();
    finalNodes = new Vector<T>();
  }

  /**
   * Get initial node of this model.
   * @return initial node of this model
   */
  public T getInitialNode(){
    return initialNode;
  }

  public boolean hasInitialNode(){
    return !(initialNode == null);
  }

  /**
   * Set initial node of this model.
   * @param initialNode
   */
  public void setInitialNode(T initialNode){
    this.initialNode = initialNode;
  }

  public boolean isFinalNode(T finalNode){
    return finalNodes.contains(finalNode);
  }

  public void addFinalNode(T finalNode){
    if (!isFinalNode(finalNode))
      finalNodes.add(finalNode);
  }

  /**
   * Get a node of this model that contain the provided instruction.
   * @param instruction the instruction that returned node contains
   * @return
   */
  public Node getNode(Instruction instruction){
    for (T node: this)
      if (node.contains(instruction))
        return node;

    return null;
  }

  /**
   * Connect two nodes. The edge connecting two nodes are added in the source node.
   * @param source the source node
   * @param target the target node that is connected by the source node
   */
  public void connect(Node source, Node target){
    Edge e = new Edge(source, target, GraphCommon.EdgeStatus.CONCRETE);
    if (!source.contains(e))
      source.getOutcomingEdges().add(e);
  }

  /**
   * Draw the model using dot language.
   * Dot file can be visualized using graphviz.
   * @param filePath
   */
  public void toDot(String filePath){
    File file = new File(filePath);
    file.delete();
    try {
      file.createNewFile();
      PrintWriter out = new PrintWriter(file.getAbsoluteFile());
      out.println("digraph G {");
      out.println("size =\"7,7\";");

      for (Node node : this){
        /* set color for nodes */
        if (node instanceof MethodNode){
          out.println("\"" + node.toDot() + "\" [color=blue,style=filled];");
        } else if (node instanceof IfNode){
          out.println("\"" + node.toDot() + "\" [color=yellow,style=filled];");
        } else {
          out.println("\"" + node.toDot() + "\" [color=green,style=filled];");
        }

        node.dotEdges(out);
      }

      out.println("}");
      out.close();
    } catch(IOException e){
      
    }
  }

}
